#include"program.h"
#include"stdlib.h"
#include"interrupt.h"
#include"stdio.h"
#include"os_modules.h"
#include"thread.h"
#include"asm_utils.h"
#include"os_constant.h"
#include"tss.h"
#include"process.h"

const int PCB_SIZE = 4096;  //PCB大小4kb
char PCB_SET[PCB_SIZE*MAX_PROGRAM_AMOUNT];  //存放PCB数组
bool PCB_SET_STATUS[MAX_PROGRAM_AMOUNT];    //PCB的分配状态
int QUEUE_TICKS[MAX_QUEUE_SIZE];    //优先队列的时间片大小
int QUEUE_AGES[MAX_QUEUE_SIZE];     //优先队列饥饿时间或等待时间或年龄限制

ProgramManager::ProgramManager()
{
    initialize();
}
void ProgramManager::initialize()
{
    allPrograms.initialize();
    // readyPrograms.initialize();
    running=nullptr;
    for(int i=0; i<MAX_QUEUE_SIZE; i++)
    {
        readyPrograms[i].initialize();
    }
    for(int i=0; i<MAX_PROGRAM_AMOUNT; i++)
    {
        PCB_SET_STATUS[i]=false;
    }
    QUEUE_TICKS[MAX_QUEUE_SIZE-1]=1;
    QUEUE_AGES[MAX_QUEUE_SIZE-1]=0;
    for(int i=MAX_QUEUE_SIZE-2; i>=0; i--)
    {
        // QUEUE_TICKS[i]=10;   //极端情况可近似时间轮转
        QUEUE_TICKS[i]=QUEUE_TICKS[i+1]*2;
        QUEUE_AGES[i]=QUEUE_TICKS[i]*10;
    }
    //初始化选择子
    int selector;
    selector = asm_add_global_descriptor(USER_CODE_LOW,USER_CODE_HIGH);
    USER_CODE_SELECTOR = (selector<<3) | 0x3;

    selector = asm_add_global_descriptor(USER_DATA_LOW,USER_DATA_HIGH);
    USER_DATA_SELECTOR = (selector<<3) | 0x3;

    selector = asm_add_global_descriptor(USER_STACK_LOW,USER_STACK_HIGH);
    USER_STACK_SELECTOR = (selector<<3) | 0x3;

    initializeTSS();
}
int ProgramManager::executeThread(ThreadFunction function,void* parameter,const char* name,int priority)
{
    //关中断，防止创建线程的过程被打断
    bool status=interruptManager.getInterruptStatus();
    interruptManager.disableInterrupt();
    //分配一页作为PCB
    PCB* thread=allocatePCB();
    if(!thread)return -1;
    memset(thread,0,PCB_SIZE);
    for(int i=0; i<MAX_PROGRAM_NAME && name[i]; i++)
    {
        thread->name[i]=name[i];
    }
    thread->status=ProgramStatus::READY;
    //此处设置优先级范围，进一步可使得一个队列对应多个优先级
    if(priority>MAX_QUEUE_SIZE-1)priority=MAX_QUEUE_SIZE-1;
    else if(priority<0)priority=0;
    thread->priority=priority;
    // thread->ticks=priority*10;
    thread->ticks=QUEUE_TICKS[priority];
    thread->ticksPassedBy=0;
    thread->waits=0;
    thread->pid=((int)thread - (int)PCB_SET)/PCB_SIZE;
    //线程栈
    thread->stack=(int*)((int)thread + PCB_SIZE-sizeof(ProcessStartStack));
    thread->stack -= 7;
    thread->stack[0]=0;
    thread->stack[1]=0;
    thread->stack[2]=0;
    thread->stack[3]=0;
    thread->stack[4]=(int)function;
    thread->stack[5]=(int)program_exit;
    thread->stack[6]=(int)parameter;
    allPrograms.push_back(&(thread->tagInAllList));	
    // readyPrograms.push_back(&(thread->tagInGeneralList));
    if(!running || priority > running->priority)
    {
        //优先级高则抢占,初始running空
        if(running)
        {
            running->status=ProgramStatus::READY;
            running->ticks=QUEUE_TICKS[running->priority];
            running->waits=0;
            readyPrograms[running->priority].push_back(&(running->tagInGeneralList));
        }
        thread->status=ProgramStatus::RUNNING;
        PCB* cur=running;
        running=thread;
        activateProgramPage(thread);
        asm_switch_thread(cur,thread);
    }else{
        readyPrograms[priority].push_back(&(thread->tagInGeneralList));
    }
    //恢复中断
    interruptManager.setInterruptStatus(status);
    return thread->pid;
}
PCB* ProgramManager::allocatePCB()
{
    for(int i=0; i<MAX_PROGRAM_AMOUNT; i++)
    {
        if(!PCB_SET_STATUS[i])
        {
            PCB_SET_STATUS[i]=true;
            return (PCB*)((int)PCB_SET + PCB_SIZE*i);
        }
    }
    return nullptr;
}  
void ProgramManager::releasePCB(PCB*  program)
{
    int index=((int)program- (int)PCB_SET)/PCB_SIZE;
    PCB_SET_STATUS[index]=false;
}
void ProgramManager::schedule_multilevel_feedback_queue()
{
    bool status=interruptManager.getInterruptStatus();
    interruptManager.disableInterrupt();
    //找到下一个执行的线程
    ListItem* item;
    for(int i=MAX_QUEUE_SIZE-1;i>=0;i--)
    {
        item=readyPrograms[i].front();
        if(item)break;
    }
    if(!item)//队列无线程
    {
        if(running->status==ProgramStatus::RUNNING)
        {
            running->ticks=QUEUE_TICKS[running->priority];
            interruptManager.setInterruptStatus(status);
            return;
        }
        printf("programManager halt...\n");
        asm_halt();
        return;
    }
    if(running->status==ProgramStatus::RUNNING)
    {
        running->status=ProgramStatus::READY;
        if(running->priority>0)running->priority--;
        running->ticks=QUEUE_TICKS[running->priority];
        running->waits=0;
        readyPrograms[running->priority].push_back(&(running->tagInGeneralList));
    }else if(running->status==ProgramStatus::DEAD){
        releasePCB(running);
    }
    PCB* next=ListItemToPCB(item,tagInGeneralList);
    PCB* cur=running;
    next->status=ProgramStatus::RUNNING;
    running=next;
    running->waits=0;
    readyPrograms[running->priority].pop_front();
    activateProgramPage(next);
    asm_switch_thread(cur,next);
    interruptManager.setInterruptStatus(status);
}
void ProgramManager::age()
{
    for(int i=MAX_QUEUE_SIZE-2; i>=0; i--)
    {   
        ListItem* item=readyPrograms[i].front();
        List raisePrograms;//提高优先级的线程
        //依次增加等待时间、年龄，达到年龄限制则升级
        while(item)
        {
            PCB* cur=ListItemToPCB(item,tagInGeneralList);
            cur->waits++;
            if(cur->waits>=QUEUE_AGES[i])
            {
                cur->waits=0;
                raisePrograms.push_back(item);
                //弹出原队列的元素
                readyPrograms[i].erase(item);
                // ListItem* temp=item;
                // item=item->previous;
                // if(temp->next)temp->next->previous=temp->previous;
                // temp->previous->next=temp->next;
                // temp->previous=temp->next=nullptr;
            }
            item=item->next;
        }
        readyPrograms[i+1].append_list(raisePrograms);
    }
}
// void ProgramManager::schedule_round_robin()
// {
    
//     bool status=interruptManager.getInterruptStatus();
//     interruptManager.disableInterrupt();
//     if(readyPrograms.size()==0)
//     {
//         interruptManager.setInterruptStatus(status);
//         return;
//     }
//     if(running->status==ProgramStatus::RUNNING)
//     {
//         running->status=ProgramStatus::READY;
//         running->ticks=running->priority*10;
//         readyPrograms.push_back(&(running->tagInGeneralList));
//     }else if(running->status==ProgramStatus::DEAD){
//         releasePCB(running);
//     }
//     ListItem* item=readyPrograms.front();
    
//     PCB* next=ListItemToPCB(item,tagInGeneralList);
//     PCB* cur=running;
//     next->status=ProgramStatus::RUNNING;
//     running=next;
//     readyPrograms.pop_front();

//     activateProgramPage(next);
//     asm_switch_thread(cur,next);
//     interruptManager.setInterruptStatus(status);
// }
// void ProgramManager::schedule_first_in_first_out()
// {
//     if(readyPrograms.size()==0)
//     {
//         printf("halt...\n");
//         asm_halt();
//         return;
//     }
//     if(running->status==ProgramStatus::DEAD)
//     {
//         releasePCB(running);
//     }
//     ListItem* item=readyPrograms.front();
//     PCB* next=ListItemToPCB(item,tagInGeneralList);
//     PCB* cur=running;
//     next->status=ProgramStatus::RUNNING;
//     running=next;
//     readyPrograms.pop_front();
//     activateProgramPage(next);
//     asm_switch_thread(cur,next);
// }
void ProgramManager::MESA_WakeUp(PCB* program)
{
    program->status = ProgramStatus::READY;
    // readyPrograms.push_front(&(program->tagInGeneralList));

    program->ticks = QUEUE_TICKS[program->priority];
    program->waits = 0;
    readyPrograms[program->priority].push_front(&(program->tagInGeneralList));//对应优先级队列
}
// void ProgramManager::Hasen_WakeUp(PCB* program)
// {
//     program->status = ProgramStatus::READY;
//     program->ticks = QUEUE_TICKS[MAX_QUEUE_SIZE-1];
//     program->waits = 0;
//     readyPrograms[MAX_QUEUE_SIZE-1].push_front(&(program->tagInGeneralList));//最高优先级，会立刻执行
// }
// void ProgramManager::Hoare_WakeUp(PCB* program)
// {
//     bool status=interruptManager.getInterruptStatus();
//     interruptManager.disableInterrupt();

//     running->status = ProgramStatus::READY;
//     // running->ticks = QUEUE_TICKS[running->priority];
//     running->waits = 0;
//     readyPrograms[MAX_QUEUE_SIZE-1].push_front(&(running->tagInGeneralList));

//     running = program;
//     running->status = ProgramStatus::RUNNING;
//     running->ticks = QUEUE_TICKS[running->priority];
//     running->waits = 0;
    
//     interruptManager.setInterruptStatus(status);
// }
void ProgramManager::initializeTSS()
{
    int size=sizeof(TSS);
    int address=(int)&tss;

    memset((char*)address,0,size);
    tss.ss0=STACK_SELECTOR; //内核态堆栈段选择子

    int low,high,limit;
    limit=size-1;
    low=(address<<16)|(limit&0xff);
    //DPL=0
    high=(address&0xff000000)|((address&0x00ff0000)>>16)|((limit&0xff00)<<16)|0x00008900;

    int selector=asm_add_global_descriptor(low,high);
    //RPL=0
    asm_ltr(selector<<3);	
    tss.ioMap=address+size;
}
int ProgramManager::executeProcess(const char* filename,int priority)
{
    bool status=interruptManager.getInterruptStatus();
    interruptManager.disableInterrupt();

    //在创建线程基础上创建进程PCB
    int pid=executeThread((ThreadFunction)load_process,(void*)filename,filename,priority);
    if(pid==-1)
    {
        interruptManager.setInterruptStatus(status);
        return -1;
    }
    //找到刚刚创建的PCB,使用pid查找
    ListItem* item=allPrograms.back();
    PCB* process=ListItemToPCB(item,tagInAllList);
    while(item!=&allPrograms.head)
    {
        if(process->pid==pid)break;
        item=item->previous;
        process=ListItemToPCB(item,tagInAllList);
    }
    // PCB* process=ListItemToPCB(allPrograms.back(),tagInAllList);
    
    //创建进程页目录表
    process->pageDirectoryAddress=createProcessPageDirectory();
    if(!process->pageDirectoryAddress)
    {
        process->status=ProgramStatus::DEAD;
        interruptManager.setInterruptStatus(status);
        return -1;
    }

    //创建进程虚拟池
    bool res=createUserVirtualPool(process);
    if(!res)
    {
        process->status=ProgramStatus::DEAD;
        interruptManager.setInterruptStatus(status);
        return -1;
    }
    interruptManager.setInterruptStatus(status);
    return pid;
}
int ProgramManager::createProcessPageDirectory()
{
    //从内核地址池中分配一页存储用户进程的页目录表
    int vaddress=memoryManager.allocatePages(AddressPoolType::KERNEL,1);
    if(!vaddress)
    {
        printf("can't create page from kernel...\n");
        return 0;
    }
    memset((char*)vaddress,0,PAGE_SIZE);

    //复制内核目录项到虚拟地址的高1GB
    int* src=(int*)(0xfffff000+0x300*4);
    int* dst=(int*)(vaddress+0x300*4);
    for(int i=0;i<256;i++)
    {
        dst[i]=src[i];
    }
    //用户进程页目录表最后一项指向用户进程页目录表本身
    ((int*)vaddress)[1023]=memoryManager.virtualAddressToPhysicalAddress(vaddress)|0x7;
    return vaddress;
}
bool ProgramManager::createUserVirtualPool(PCB* process)
{
    int sourcesCount = (0xc0000000-USER_VADDR_START)/PAGE_SIZE;
    int bitmapLength=ceil(sourcesCount,8);
    //计算位图所占的页数
    int pagesCount=ceil(bitmapLength,PAGE_SIZE);
    int start=memoryManager.allocatePages(AddressPoolType::KERNEL,pagesCount);
    if(!start)
    {
        return false;
    }
    memset((char*)start,0,PAGE_SIZE*pagesCount);
    (process->userVirtual).initialize((char*)start,bitmapLength,USER_VADDR_START);
    return true;
}
void ProgramManager::activateProgramPage(PCB* program)
{
    int paddress=PAGE_DIRECTORY;
    if(program->pageDirectoryAddress)
    {
        tss.esp0=(int)program+PAGE_SIZE;
        paddress=memoryManager.virtualAddressToPhysicalAddress(program->pageDirectoryAddress);
    }
    asm_update_cr3(paddress);
}
void program_exit()
{
    PCB* thread=programManager.running;
    thread->status=ProgramStatus::DEAD;
    programManager.schedule_multilevel_feedback_queue();
    // programManager.schedule_first_in_first_out();
    // if(thread->pid)
    // {
    //     programManager.schedule_round_robin();
    // }else{
    //     interruptManager.disableInterrupt();
    //     printf("halt...\n");
    //     asm_halt();
    // }
}
void load_process(const char* filename)
{
    interruptManager.disableInterrupt();

    PCB* process=programManager.running;
    ProcessStartStack* interruptStack = (ProcessStartStack*)((int)process+PAGE_SIZE-sizeof(ProcessStartStack));
    interruptStack->edi=0;
    interruptStack->esi=0;
    interruptStack->ebp=0;
    interruptStack->esp_dummy=0;
    interruptStack->ebx=0;
    interruptStack->edx=0;
    interruptStack->ecx=0;
    interruptStack->eax=0;
    interruptStack->gs=0;

    interruptStack->fs=programManager.USER_DATA_SELECTOR;  
    interruptStack->es=programManager.USER_DATA_SELECTOR;
    interruptStack->ds=programManager.USER_DATA_SELECTOR;

    interruptStack->eip=(int)filename;
    interruptStack->cs=programManager.USER_CODE_SELECTOR;   //用户模式平坦模式
  
    interruptStack->eflags=(0<<12)|(1<<9)|(1<<1);   //IOPL，IF=1开中断，MBS=1默认

    interruptStack->esp=memoryManager.allocatePages(AddressPoolType::USER,1);
    if(interruptStack->esp==0)
    {
        printf("can't build process!\n");
        process->status=ProgramStatus::DEAD;
        asm_halt();
    }
    interruptStack->esp += PAGE_SIZE;
    interruptStack->ss=programManager.USER_STACK_SELECTOR;

    asm_start_process((int)interruptStack);
}